<template>
  <Codemirror
    v-model="model"
    :readonly="props.readonly"
    :style="props.codeStyle"
    :autofocus="true"
    :extensions="extensions"
    @ready="handleReady"
    @change="onChange"
    @focus="onFocus"
    @blur="onBlur"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { yaml } from '@codemirror/lang-yaml'
import { sql, StandardSQL } from '@codemirror/lang-sql'
import { xml } from '@codemirror/lang-xml'
import { javascript } from '@codemirror/lang-javascript'
import { html } from '@codemirror/lang-html'
import { json } from '@codemirror/lang-json'
import { css } from '@codemirror/lang-css'
import { java } from '@codemirror/lang-java'
import { oneDark } from '@codemirror/theme-one-dark'
import { CompletionContext, snippetCompletion } from '@codemirror/autocomplete'

import { CodeProps, langCode } from './types'
import { EditorView } from '@codemirror/view'

// 提供一个默认值
const model = defineModel({ type: String, default: '', required: true })
const emits = defineEmits(['update:modelValue', 'ready', 'change', 'focus', 'blur'])
const props = withDefaults(defineProps<CodeProps>(), {
  code: 'javascript'
})

const extensions = ref<any[]>()

function sqlCompletions(context: CompletionContext) {
  let word = context.matchBefore(/\w*/)
  if (word == null || (word.from == word.to && !context.explicit)) {
    return null
  }
  return {
    from: word.from,
    options: [
      snippetCompletion('--[ ${表达式} ]--', {
        label: 'bds',
        type: 'text',
        detail: 'Beet模版表达式'
      }),
      snippetCompletion('--[ if(${表达式}){ ]--\n\n--[ } ]--', {
        label: 'bdsif',
        type: 'text',
        detail: 'if条件'
      }),
      snippetCompletion('@${查询参数占位}', {
        label: 'bdszw',
        type: 'text',
        detail: '查询参数转义'
      }),
      snippetCompletion('isEmpty(${参数})', {
        label: 'bdsisEmpty',
        type: 'text',
        detail: ' 判断变量或者表达式为空'
      }),
      snippetCompletion('isNotEmpty(${参数})', {
        label: 'bdsisNotEmpty',
        type: 'text',
        detail: '判断变量或者表达式不为空'
      }),
      snippetCompletion('nvl(${参数1},${参数2})', {
        label: 'bdsnvl',
        type: 'text',
        detail: '函数nvl，如果对象为null，则返回第二个参数，否则，返回自己 nvl(user,"不存在")'
      }),
      snippetCompletion('trim(${参数1},${参数2})', {
        label: 'bdstrim',
        type: 'text',
        detail:
          '截取数字或者日期，返回字符,如trim(12.456,2)返回"12.45",trim(date,\'yyyy\')返回"2017"'
      })
    ]
  }
}

const jsSnippets = StandardSQL.language.data.of({
  autocomplete: sqlCompletions
})

const checkCode = (lang: langCode) => {
  //'yaml' | 'sql' | 'xml' | 'javascript' | 'html' | 'json' | 'css' | 'java'
  if (lang == 'yaml') {
    extensions.value = [yaml(), oneDark]
  } else if (lang == 'sql') {
    extensions.value = [sql(), jsSnippets, EditorView.lineWrapping, oneDark]
  } else if (lang == 'xml') {
    extensions.value = [xml(), oneDark]
  } else if (lang == 'html') {
    extensions.value = [html(), oneDark]
  } else if (lang == 'json') {
    extensions.value = [json(), oneDark]
  } else if (lang == 'css') {
    extensions.value = [css(), oneDark]
  } else if (lang == 'java') {
    extensions.value = [java(), oneDark]
  } else {
    extensions.value = [javascript(), oneDark]
  }
}
checkCode(props.code)

function handleReady(payload: any) {
  emits('ready', payload)
}
function onChange(value: string, viewUpdate: any) {
  emits('change', value, viewUpdate)
  emits('update:modelValue', value)
}
function onFocus(viewUpdate: any) {
  emits('focus', viewUpdate)
}
function onBlur(viewUpdate: any) {
  emits('blur', viewUpdate)
}

defineExpose({ checkCode })
</script>
<style scoped>
:deep(.cm-editor) {
  border-radius: 8px;
  outline: none;
  border: 1px solid transparent;
  .cm-scroller {
    border-radius: 8px;
  }
}
</style>
